package com.weilive.core.code.parsers;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class ProtoFileParser {

	private static String Field_Prefix = "f_";
	private static HashMap<String, String> type_maps = new HashMap<String, String>();
	static {
		type_maps.put("string", "String");
		type_maps.put("int32", "Integer");
		type_maps.put("int64", "Long");
		type_maps.put("float", "Float");
		type_maps.put("double", "Double");
		type_maps.put("bool", "Boolean");
		type_maps.put("bytes", "byte[]");
	}

	private static String getType(String type, boolean repeated) {
		String ret = type_maps.get(type);
		if (ret == null) ret = type;
		return repeated ? String.format("List<%s>", ret) : ret;
	}

	public static class Field {
		public String base_type;
		public String type;
		public String name;
		public String full_name;
		public String comment;
		
		public String getTypeComment() {
			return comment.length() == 0 ? "// [" + type +"]" : comment + " [" + type +"]";
		}
		
		public boolean isInt() {
			return base_type.equals("int32");
		}
		
		public boolean isLong() {
			return base_type.equals("int64");
		}
		
		public boolean isBool() {
			return base_type.equals("bool");
		}
		
		public boolean isFloat() {
			return base_type.equals("float");
		}
		
		public boolean isDouble() {
			return base_type.equals("double");
		}
		
		public boolean isString() {
			return base_type.equals("string");
		}
		
		public boolean isArray() {
			return type.startsWith("List");
		}
		
		public boolean isMessage() {
			return !isInt() && !isLong() && !isBool() && !isDouble() && !isFloat() && !isString();
		}
	}

	public static class Message {
		public String name;
		public boolean hasList = false;
		public List<Field> fields = new ArrayList<Field>();
	}
	
	public static class ProtoFile {
		public String package_name;
		public String java_package;
		public String java_outer;
		public List<Message> messages = new ArrayList<Message>();
		public Message get(String name) {
			for (Message message : messages) {
				if (message.name.equals(name)) {
					return message;
				}
			}
			return null;
		}
	}

	public static ProtoFile parse(File file) throws Exception {
		ProtoFile result = new ProtoFile();
		BufferedReader reader = new BufferedReader(new FileReader(file));
		String line;
		while ((line = reader.readLine()) != null) {
			line = line.trim();
			if (line.startsWith("package")) 
			{
				result.package_name = line.split(" ")[1].replace(";", "");
			}
			else if (line.startsWith("option") && line.contains("java_package")) 
			{
				int pos1 = line.indexOf('"');
				int pos2 = line.indexOf('"', pos1+1);
				result.java_package = line.substring(pos1+1, pos2);
			}
			else if (line.startsWith("option") && line.contains("java_outer_classname")) 
			{
				int pos1 = line.indexOf('"');
				int pos2 = line.indexOf('"', pos1+1);
				result.java_outer = line.substring(pos1+1, pos2);
			}
			else if (line.startsWith("message")) 
			{
				String [] names = line.split(" ");
				Message message = new Message();
				message.name = names[1].trim();
				result.messages.add(message);

				while ((line = reader.readLine()) != null) {
					line = line.trim();
					if (line.startsWith("enum") || line.startsWith("message")) {
						int count = 1;
						while ((line = reader.readLine()) != null) {
							if (line.contains("{")) count ++;
							if (line.contains("}")) count --;
							if (count == 0) {
								break;
							}
						}
						continue;
					}
					if (line.startsWith("optional") || line.startsWith("required") || line.startsWith("repeated")) {
						String[] sub_names = line.split(" ");
						boolean repeated = line.startsWith("repeated");
						if (repeated) message.hasList = true;
						Field field = new Field();
						field.base_type = sub_names[1].trim();
						field.type = getType(field.base_type, repeated);
						field.full_name = sub_names[2].trim();
						field.name = field.full_name.replaceFirst(Field_Prefix, "");
						int comment_idx = line.indexOf("//");
						field.comment = comment_idx > 0 ? line.substring(comment_idx) : "";
						
						message.fields.add(field);
					} else if (line.contains("}")) {
						break;
					}
				}
			}
		}
		reader.close();
		return result;
	}
}
